home *** CD-ROM | disk | FTP | other *** search
- /*
- * mp (Midi Play)
- *
- * This program is largely derived from a program
- * 'mftext' by Tim Thompson, and a programs 'transcribe'
- * and 'adagio' by Roger Dannenberg. Much of the code
- * for playing the SoundBlaster card came from 'fmplay'
- * by Hannu Savolainen (hsavolai@cs.helsinki.fi) with
- * modifications by Rob Hooft (hooft@chem.ruu.nl).
- *
- * Greg Lee, lee@uhunix.uhcc.hawaii.edu
- * 1/30/93
- */
-
-
- #include <stdio.h>
- #include <ctype.h>
- #include "midifile.h"
- #include "midi.h"
-
- static FILE *F;
-
- #include "cext.h"
- #include <malloc.h>
- #include "midicode.h"
- #include "adagio.h"
- #include "userio.h"
- #include "cmdline.h"
- #include "vname.h"
-
- void phase2();
-
- #define MAXSPACE 500000
- /* the free space counter */
- long space = MAXSPACE;
-
- #ifndef XPOLYPHANY
- #define XPOLYPHANY 48
- #endif
- #ifndef XMAXCHAN
- #define XMAXCHAN 16
- #endif
-
- #define NO_VOI -1
- int program[num_voices] = { NO_VOI,NO_VOI,NO_VOI,NO_VOI,NO_VOI,NO_VOI,
- NO_VOI,NO_VOI,NO_VOI,NO_VOI,NO_VOI,NO_VOI,NO_VOI,NO_VOI,NO_VOI,NO_VOI };
- int ext_program[num_voices] = { NO_VOI,NO_VOI,NO_VOI,NO_VOI,NO_VOI,NO_VOI,
- NO_VOI,NO_VOI,NO_VOI,NO_VOI,NO_VOI,NO_VOI,NO_VOI,NO_VOI,NO_VOI,NO_VOI };
- int ext_chan[num_voices] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
- int ext_poly[num_voices] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
- int ext_pan[num_voices] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 };
- private int ext_polyphony = 0;
-
- /****************************************************************************
- * Variables set by command line switches
- ****************************************************************************/
-
- /****************************************************************************
- * Data for command line parsing
- ****************************************************************************/
- #define nswitches 16
- private char *switches[nswitches] =
- { "-help", "-v",
- "-init", "-i",
- "-trace", "-t",
- "-external", "-e",
- "-drum", "-d",
- "-midi", "-m",
- "-adagio", "-a", "-p", "-s" };
-
- #define noptions 1
- private char *options[noptions] = { "-tune" };
- #define n_t_sw 2
- private char *t_switches[n_t_sw] = { "-t", "-trace" };
- #define n_a_sw 2
- private char *a_switches[n_a_sw] = { "-a", "-adagio" };
- #define n_d_sw 2
- private char *d_switches[n_d_sw] = { "-d", "-drum" };
-
-
- /****************************************************************************
- * Routines local to this module
- ****************************************************************************/
- private void cmdline_help();
-
- /****************************************************************************
- * cmdline_help
- * Effect:
- * Prints out command line help
- ****************************************************************************/
-
- private void cmdline_help()
- {
- fprintf(stderr,"mp [options] filename [options]\n");
- fprintf(stderr," -help this message\n");
- fprintf(stderr," -init (-i) initialize channels\n");
- fprintf(stderr," -v print note data\n");
- fprintf(stderr," -tune file use tuning from file\n");
- fprintf(stderr," -drum (-d) drum mode\n");
- fprintf(stderr," -trace (-t) trace music\n");
- fprintf(stderr," -adagio (-a) adagio file on stdout\n");
- }
-
-
- boolean ad_print = false; /* adagio output */
- boolean piano_only = false; /* ignore voice requests */
- boolean verbose = false; /* verbose flag for this module */
- boolean vverbose = false; /* tracing output */
- boolean drum_mode = false;
- boolean percsel = PSELECT;
-
- int max_m_notes = -1; /* -1 is flag that space must be allocated */
-
- /****************************************************************
- * data structure m_notes: the midi stream is stored as an array
- * of 4-byte records, each of which is either a time or midi
- * data. Midi data always begins with a control byte (high
- * order bit set), and it is assumed times are positive (high
- * order bit clear), so the two are easy to distinguish
- * IF THE COMPILER PUTS THESE BITS IN THE SAME PLACE. It looks
- * like the high order byte of the time lines up with the last
- * byte of a 4 byte array, so we will always set the high order
- * bit of the last array byte when the first 3 bytes are filled
- * with MIDI data. This is refered to as the "tag" bit.
- * WARNING: Lattice C longs are UNSIGNED, therefore always
- * positive. Test the high order bit with a mask.
- ****************************************************************/
-
- #define MIDI_CMD_BIT 0x80
- #define HIGH_BIT 0x80000000
- #define istime(note) (!(((note)->when) & HIGH_BIT))
-
- typedef union m_note_struct {
- byte n[4];
- long when;
- } *m_note_type, m_note_node;
-
- private m_note_type event_buff; /* pointer to allocated buffer */
- private m_note_type next; /* pointer to next entry in buffer */
- private m_note_type last; /* pointer to last entry in buffer */
- private int pile_ups; /* inner loop iteration count */
- private int max_pile; /* maximum of pile_ups */
-
- private int m_division = 96;
- private int m_track = -1;
- private long m_tempo = 500000;
-
- /****************************************************************************
- * Routines local to this module
- ****************************************************************************/
- private void bend_filter();
- private void byteorder();
- private void ctrl_filter();
- private int event_bend();
- private void filter();
- private long getdur();
- private long getnext();
- private long diffnext();
- private char map_ctrl();
- private char map_nctrl();
- private event_type phasem();
- private void put_pitch();
- private void rec_init();
- private void stowevent();
- private event_type rec_final();
- private long m_time();
- /*************************/
-
- filegetc()
- {
- return(getc(F));
- }
-
- main(argc,argv)
- int argc;
- char **argv;
- {
- char *s;
-
- cl_init(switches, nswitches, options, noptions, argv, argc);
-
- if (cl_switch("-help")) {
- cmdline_help();
- return;
- }
- if (cl_switch("-v")) verbose = 1;
- piano_only = cl_switch("-p");
- ad_print = (cl_nswitch(a_switches, n_a_sw) != NULL);
- vverbose = (cl_nswitch(t_switches, n_t_sw) != NULL);
- drum_mode = (cl_nswitch(d_switches, n_d_sw) != NULL);
-
- if ((s = cl_arg(1)) != NULL)
- F = fileopen(s, "mid", "r", "Midi song file");
- else
- F = stdin;
-
- rec_init();
- initfuncs();
- Mf_getc = filegetc;
- midifile();
- fclose(F);
- if (ad_print)
- (void)rec_final(true); /* write out recorded data, */
- /* suppress time of first event*/
- else phase2((rec_final(true)));
- exit(0);
- }
-
-
- error(s)
- char *s;
- {
- fprintf(stderr,"Error: %s\n",s);
- }
-
- txt_header(format,ntrks,division)
- {
- m_division = division;
- if (!vverbose) return;
- printf("*Header format=%d ntrks=%d division=%d\n",format,ntrks,division);
- }
-
- txt_trackstart()
- {
- Mf_currtime = 0;
- m_track++;
- if (!vverbose) return;
- printf("Start track %d\n", m_track);
- }
-
- txt_trackend()
- {
- if (!vverbose) return;
- printf("End track %d\n", m_track);
- }
-
- static int repeat_drum = -1;
- static int rd_chan, rd_pitch, rd_vol, repeat_vol;
- static long rd_time;
-
- txt_noteon(chan,pitch,vol)
- {
- if (percsel&(1 << chan)) {
- if (pitch > 81) {
- if (vol) repeat_drum = pitch;
- repeat_vol = vol;
- return;
- }
- else if (pitch < 35) return;
- else if (vol) {
- rd_chan = chan;
- rd_pitch = pitch;
- rd_vol = vol;
- rd_time = Mf_currtime;
- }
- }
- else repeat_drum = -1;
-
- if (program[chan] == NO_VOI) txt_program(chan,0);
-
- if (ext_chan[chan] && program[chan] == ext_program[ext_chan[chan]-1]) {
- if (!vol) {
- ext_polyphony--;
- ext_poly[chan]--;
- }
- else if (ext_polyphony < XPOLYPHANY) {
- ext_polyphony++;
- ext_poly[chan]++;
- }
- else {
- ext_chan[chan] = 0;
- ext_polyphony -= ext_poly[chan];
- ext_poly[chan] = 0;
- if (verbose)
- printf("too many notes on channel %d with voice %d\n", chan+1, program[chan]-1);
- }
- }
- stowevent(NOTEON, chan, pitch, vol);
- }
-
- txt_noteoff(chan,pitch,vol)
- {
- if (percsel&(1 << chan)) {
- if (repeat_drum == pitch && chan == rd_chan) {
- long now = Mf_currtime;
- int roll_sep = 8;
- int roll_cnt = repeat_drum - 81 + 1;
- Mf_currtime = rd_time;
- while (1) {
- Mf_currtime += 2;
- stowevent(NOTEON, chan, rd_pitch, 0);
- if (!roll_cnt) break;
- roll_cnt--;
- Mf_currtime += roll_sep;
- stowevent(NOTEON, chan, rd_pitch, repeat_vol);
- }
- repeat_drum = -1;
- Mf_currtime = now;
- }
- else if (pitch < 35 || pitch > 81) return;
- }
-
- if (ext_chan[chan] && program[chan] == ext_program[ext_chan[chan]-1]) {
- ext_polyphony--;
- ext_poly[chan]--;
- }
- stowevent(NOTEON, chan, pitch, 0);
- }
-
- txt_pressure(chan,pitch,press)
- {
- stowevent(PRESSURE, chan, pitch, press);
- }
-
- txt_parameter(chan,control,value)
- {
- stowevent(CONTROLLER, chan, control, value);
- }
-
- txt_pitchbend(chan,msb,lsb)
- {
- stowevent(PITCHBEND, chan, msb, lsb);
- }
-
- txt_program(chan,prog)
- {
- static int ext_tot = 0;
- int n;
-
- program[chan] = prog + 1;
-
- if (!ext_chan[chan] &&
- !(percsel&(1 << chan)) &&
- ext_tot < XMAXCHAN &&
- #ifdef K1
- sub_voice[prog].newv >= 0) {
- #else
- XSELECT&(1 << chan)) {
- #endif
- ext_program[ext_tot] = prog + 1;
- ext_tot++;
- ext_chan[chan] = ext_tot;
- }
- stowevent(PROGRAM, chan, prog + 1, 0);
- }
-
- txt_chanpressure(chan,press)
- {
- stowevent(CHANPRESSURE, chan, press, 0);
- }
-
- txt_sysex(leng,mess)
- char *mess;
- {
- if (!vverbose) return;
- if (vverbose) prtime();
- printf("Sysex, leng=%d\n",leng);
- }
-
- txt_metamisc(type,leng,mess)
- char *mess;
- {
- if (!vverbose) return;
- prtime();
- printf("Meta event, unrecognized, type=0x%02x leng=%d\n",type,leng);
- }
-
- txt_metaspecial(type,leng,mess)
- char *mess;
- {
- if (!verbose) return;
- if (vverbose) prtime();
- printf("Meta event, sequencer-specific, type=0x%02x leng=%d\n",type,leng);
- }
-
- txt_metatext(type,leng,mess)
- char *mess;
- {
- static char *ttype[] = {
- NULL,
- "note", /* type=0x01 */
- "Copyright Notice", /* type=0x02 */
- "Sequence/Track Name",
- "Instrument Name", /* ... */
- "Lyric",
- "Marker",
- "Cue Point", /* type=0x07 */
- "note"
- };
- int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1;
- register int n, c;
- register char *p = mess;
-
- if (!verbose) return;
- if ( type < 1 || type > unrecognized )
- type = unrecognized;
- if (vverbose) prtime();
- printf(" %s: ", ttype[type]);
- for ( n=0; n<leng; n++ ) {
- c = *p++;
- printf( (isprint(c)||isspace(c)) ? "%c" : "\\0x%02x" , c);
- }
- printf("\n");
- }
-
- txt_metaseq(num)
- {
- if (!vverbose) return;
- prtime();
- printf("Meta event, sequence number = %d\n",num);
- }
-
- txt_metaeot()
- {
- if (!vverbose) return;
- prtime();
- printf("Meta event, end of track\n");
- }
-
- txt_keysig(sf,mi)
- {
- if (!vverbose) return;
- prtime();
- printf("Key signature, sharp/flats=%d minor=%d\n",sf,mi);
- }
-
- txt_tempo(tempo)
- long tempo;
- {
- m_tempo = tempo;
- if (!vverbose) return;
- prtime();
- printf("Tempo, microseconds-per-MIDI-quarter-note=%d\n",tempo);
- }
-
- txt_timesig(nn,dd,cc,bb)
- {
- int denom = 1;
-
- if (!vverbose) return;
- while ( dd-- > 0 )
- denom *= 2;
- prtime();
- printf("Time signature=%d/%d MIDI-clocks/click=%d 32nd-notes/24-MIDI-clocks=%d\n",
- nn,denom,cc,bb);
- }
-
- txt_smpte(hr,mn,se,fr,ff)
- {
- if (!vverbose) return;
- prtime();
- printf("SMPTE, hour=%d minute=%d second=%d frame=%d fract-frame=%d\n",
- hr,mn,se,fr,ff);
- }
-
- txt_arbitrary(leng,mess)
- char *mess;
- {
- if (!vverbose) return;
- prtime();
- printf("Arbitrary bytes, leng=%d\n",leng);
- }
-
- prtime()
- {
- printf("Time=%ld (%ldcs) ", Mf_currtime,m_time());
- }
-
- initfuncs()
- {
- Mf_error = error;
- Mf_header = txt_header;
- Mf_trackstart = txt_trackstart;
- Mf_trackend = txt_trackend;
- Mf_noteon = txt_noteon;
- Mf_noteoff = txt_noteoff;
- Mf_pressure = txt_pressure;
- Mf_parameter = txt_parameter;
- Mf_pitchbend = txt_pitchbend;
- Mf_program = txt_program;
- Mf_chanpressure = txt_chanpressure;
- Mf_sysex = txt_sysex;
- Mf_metamisc = txt_metamisc;
- Mf_seqnum = txt_metaseq;
- Mf_eot = txt_metaeot;
- Mf_timesig = txt_timesig;
- Mf_smpte = txt_smpte;
- Mf_tempo = txt_tempo;
- Mf_keysig = txt_keysig;
- Mf_seqspecific = txt_metaspecial;
- Mf_text = txt_metatext;
- Mf_arbitrary = txt_arbitrary;
- }
- /****************************/
-
- /* record.c -- keyboard to adagio recorder
- *
- * the interface consists of three routines:
- * rec_init() -- initialization
- * stowevent() -- store each midi event as encountered
- * rec_final() -- called to finish up
- */
-
- /*****************************************************************************
- * Change Log
- * Date | Change
- *-----------+-----------------------------------------------------------------
- * 27-Feb-86 | Created changelog
- * | Use pedal information when computing durations (code taken
- * | from transcribe.c)
- * 23-Mar-86 | Determine size of transcription when rec_init is called.
- * 21-May-86 | Major rewrite to use continuous controls (code taken
- * | from transcribe.c)
- *****************************************************************************/
-
- private void stowevent(command, chan, s1, s2)
- int command;
- {
- next->when = m_time();
- next++;
- next->n[0] = command | chan;
- next->n[1] = s1;
- next->n[2] = s2;
- next->n[3] = MIDI_CMD_BIT | m_track; /* set tag bit */
- next++;
-
- if (next >= last) {
- fprintf(stderr,"out of space\n");
- exit(1);
- }
- }
-
- /****************************************************************************
- * bend_filter
- * Inputs:
- * m_note_type m_note: the current m_note
- * m_note_type last: the last recorded event
- * long now: the current time
- * Effect:
- * remove pitch bend events in same 0.01 sec time slot
- * Implementation:
- * If the current event is a pitch bend that bends again
- * in the same time slot, make it a no-op by replacing it with
- * the time.
- ****************************************************************************/
-
- private void bend_filter(m_note, last, now)
- m_note_type m_note; /* current m_note */
- m_note_type last; /* the last recorded event */
- long now; /* the current time */
- {
- /* first see if there is another bend in this time
- * slot.
- */
- m_note_type m_note2 = m_note + 1;
- while (m_note2 < last) {
- if (istime(m_note2) && (m_note2->when > now)) {
- break; /* new time slot */
- } else if (m_note->n[0] == m_note2->n[0]) {
- m_note->when = now;
- return; /* found another bend */
- }
- m_note2++;
- }
- }
-
- /****************************************************************************
- * byteorder
- * Effect:
- * check out assumptions about byte order and placement
- ****************************************************************************/
-
- private void byteorder()
- {
- if ((sizeof(event_buff[0]) != 4) ||
- (sizeof(event_buff[0].when) != 4) ||
- (sizeof(event_buff[0].n[0]) != 1)) {
- fprintf(stderr, "implementation error: size problem\n");
- exit(1);
- }
- event_buff[0].n[0] = 0x12;
- event_buff[0].n[1] = 0x34;
- event_buff[0].n[2] = 0x56;
- event_buff[0].n[3] = 0x78;
- /**
- if (verbose)
- printf("layout is 0x%lx\n", event_buff[0].when);
- **/
- if ((event_buff[0].when != 0x78563412) &&
- (event_buff[0].when != 0x12345678)) {
- fprintf(stderr, "implementation error: layout problem\n");
- exit(1);
- }
- }
-
- /****************************************************************************
- * ctrl_filter
- * Inputs:
- * m_note_type m_note: the current m_note
- * m_note_type last: the last recorded event
- * long now: the current time
- * Effect:
- * remove ctrl change events in same 0.01 sec time slot
- * Implementation:
- * If the current event is a control change that changes again
- * in the same time slot, make it a no-op by replacing it with
- * the time.
- ****************************************************************************/
-
- private void ctrl_filter(m_note, last, now)
- m_note_type m_note; /* the current m_note */
- m_note_type last; /* the last recorded event */
- long now; /* the current time */
- {
- /* see if there is another control change in this time
- * slot.
- */
- m_note_type m_note2 = m_note+1;
- while (m_note2 < last) {
- if (istime(m_note2) && (m_note2->when > now)) {
- break; /* new time slot */
- } else if ((m_note->n[0] == m_note2->n[0]) &&
- (m_note->n[1] == m_note2->n[1])) {
- m_note->when = now;
- return; /* found another change */
- }
- m_note2++;
- }
- }
-
- /****************************************************************************
- * event_bend
- * Inputs:
- * m_note_type m_note: pointer to a pitch bend event
- * Outputs:
- * returns int: an 8 bit pitch bend number
- ****************************************************************************/
-
- private int event_bend(m_note)
- m_note_type m_note;
- {
- return (int) (((m_note->n[1]) >> 6) + ((m_note->n[2]) << 1));
- }
-
- /****************************************************************************
- * filter
- * Inputs:
- * m_note_type last: the last m_note recorded
- * Effect: allow only one control change per time slot (0.01 sec)
- * Implementation:
- * call ctrl_filter and bend_filter to overwrite control changes with
- * noop data (the current time is used as a noop)
- ****************************************************************************/
-
- private void filter(last)
- m_note_type last;
- {
- m_note_type m_note; /* loop control variable */
- long now; /* last time seen */
- int command; /* command pointed to by m_note */
- int chan; /* channel pointed to by m_note */
-
- for (m_note = event_buff; m_note <= last; m_note++) {
- if (istime(m_note)) {
- now = m_note->when;
- } else {
- command = m_note->n[0] & MIDI_CODE_MASK;
- chan = m_note->n[0] & MIDI_CHN_MASK;
-
- if (command == MIDI_CTRL &&
- m_note->n[1] == SUSTAIN) {
- /* do nothing */;
- } else if (command == MIDI_CTRL) {
- ctrl_filter(m_note, last, now);
- } else if (command == MIDI_TOUCH) {
- bend_filter(m_note, last, now); /* bend and touch use the */
- } else if (command == MIDI_BEND) { /* same filter routines */
- bend_filter(m_note, last, now);
- }
- }
- }
- }
-
-
- /****************************************************************************
- * getdur
- * Inputs:
- * int i: index of the m_note
- * m_note_type last: pointer to the last event recorded
- * int ped: true if pedal is down at event i
- * long now: the time at event i
- * Outputs:
- * returns long: the duration of m_note i
- * Assumes:
- * assumes i is a m_note
- * Implementation:
- * This is tricky because of pedal messages. The m_note is kept on by
- * either the key or the pedal. Keep 2 flags, key and ped. Key is
- * turned off when a key is released, ped goes off and on with pedal.
- * Note ends when (1) both key and ped are false, (2) key is
- * pressed (this event will also start another m_note).
- ****************************************************************************/
-
- private long getdur(i, last, ped, now, solo)
- int i;
- m_note_type last;
- int ped;
- long now;
- int solo;
- {
- int key = true; /* flag that says if m_note is on */
- long start = now;
- long lastnow = now;
- int thetrack = event_buff[i].n[3] & 0x7f;
- int chan = event_buff[i].n[0] & MIDI_CHN_MASK;
- int pitch = event_buff[i].n[1];
- m_note_type m_note = &(event_buff[i+1]);
- int m_noteon; /* true if a m_noteon message received on chan */
- int keyon; /* true if m_noteon message had non-zero velocity */
- int newsolo;
-
- /* search from the next event (i+1) to the end of the buffer:
- */
- for (; m_note < last; m_note++) {
- if (istime(m_note)) {
- now = m_note->when;
- /** this might interfere with roll notes
- if (now < lastnow) return(lastnow - start);
- **/
- } else {
- if (thetrack != (m_note->n[3] & 0x7f)) return(lastnow - start);
- /**
- if (thetrack != (m_note->n[3] & 0x7f)) fprintf(stderr,"no term: from %d found %d\n",
- thetrack, m_note->n[3] & 0x7f);
- **/
- newsolo = m_noteon = keyon = false;
- if ((m_note->n[0] & MIDI_CHN_MASK) == chan) {
- if ((m_note->n[0] & MIDI_CODE_MASK) == MIDI_CTRL &&
- m_note->n[1] == ALL_NOTES_OFF) return(now - start);
- m_noteon = ((m_note->n[0] & MIDI_CODE_MASK) == MIDI_ON_NOTE) &&
- (m_note->n[1] == pitch);
- if (solo) newsolo = ((m_note->n[0] & MIDI_CODE_MASK) == MIDI_ON_NOTE) &&
- (m_note->n[1] != pitch) && (m_note->n[2] != 0);
- keyon = m_noteon && (m_note->n[2] != 0);
- if ((m_noteon && (m_note->n[2] == 0)) ||
- (((m_note->n[0] & MIDI_CODE_MASK) == MIDI_OFF_NOTE) &&
- (m_note->n[1] == pitch))) key = false;
- if (((m_note->n[0] & MIDI_CODE_MASK) == MIDI_CTRL) &&
- m_note->n[1] == SUSTAIN && m_note->n[2] == 127) ped = true;
- if (((m_note->n[0] & MIDI_CODE_MASK) == MIDI_CTRL) &&
- m_note->n[1] == SUSTAIN && m_note->n[2] == 0) ped = false;
-
- if ((!key && !ped) || keyon || newsolo)
- return now - start;
- }
- }
- lastnow = now;
- }
- return last->when - start;
- }
-
- /****************************************************************************
- * getnext
- * Inputs:
- * int i: the index of the current m_note
- * m_note_type last: pointer to last valid data
- * long now: the current time
- * Outputs:
- * returns long: the time of the next m_note, program, or control change
- * (returns time of last event if nothing else is found)
- ****************************************************************************/
-
- private long getnext(i, last, now)
- int i; /* the index of the current m_note */
- m_note_type last; /* pointer to last valid data */
- long now; /* the current time */
- {
- long lastnow = now;
- int thetrack = event_buff[i].n[3] & 0x7f;
-
- i++; /* advance to next item */
- for (; event_buff + i < last; i++) {
- m_note_type m_note = &(event_buff[i]);
- int cmd = m_note->n[0] & MIDI_CODE_MASK;
-
- if (istime(m_note)) {
- now = m_note->when;
- if (now < lastnow) return(-1);
- lastnow = now;
- } else {
- if ((m_note->n[3] & 0x7f) != thetrack) return(-1);
- if (((cmd == MIDI_ON_NOTE) &&
- (m_note->n[2] != 0)) /* m_note on */ ||
- (cmd == MIDI_CH_PROGRAM) /* program change */ ||
- ((cmd == MIDI_CTRL) &&
- (map_nctrl(m_note->n[1]) < 7)
- /*(m_note->n[1] != SUSTAIN)*/ /* control change */ ) ||
- (cmd == MIDI_TOUCH) ||
- (cmd == MIDI_BEND)) {
- return now;
- }
- }
- }
- return last->when;
- }
-
- /****************************************************************************
- * map_ctrl
- * Inputs:
- * int control: a midi control number
- * Outputs:
- * returns char: an adagio control change command letter, NULL if
- * control change is not one of PORTARATE, PORTASWITCH,
- * MODWHEEL, FOOT
- ****************************************************************************/
-
- private char map_ctrl(control)
- int control;
- {
- switch (control) {
- case PORTARATE: return 'J';
- case PORTASWITCH: return 'K';
- case MODWHEEL: return 'M';
- case FOOT: return 'X';
- default: return 0;
- }
- }
-
- private char map_nctrl(control)
- int control;
- {
- switch (control) {
- case PORTARATE: return 1;
- case PORTASWITCH: return 2;
- case MODWHEEL: return 3;
- case FOOT: return 5;
- case VOLUME: return 7;
- case PAN: return 8;
- case EXPRESSION: return 9;
- default: return 15;
- }
- }
-
- private long diffnext(i, last, now, nxlie)
- int i; /* the index of the current m_note */
- m_note_type last; /* pointer to last valid data */
- long now; /* the current time */
- boolean *nxlie;
- {
- now = getnext(i, last, now) - now;
- if (now < 0) {
- *nxlie = true;
- return 0;
- }
- *nxlie = false;
- return now;
- }
-
- /* beginning of interface to adagio "phase1" routines */
-
- /****************************************************************************
- * The following are used to simulate fixed point with the radix point
- * 8 bits from the right:
- ****************************************************************************/
- #define unity 256
- #define round(x) (((x)+128)>>8)
- #define precise(x) ((x)<<8)
-
-
- private void reverse();
- private event_type nalloc();
- private event_type ctrlalloc();
- private void ins_event();
-
-
- private boolean pitch_flag; /* set when a pitch is indicated */
- /* (if controls changes are given, only allocate a note event if
- * a pitch was specified -- i.e. when pitch_flag is set)
- */
- private boolean rest_flag; /* set when a rest (R) is found */
- /* this flag is NOT inherited by the next line */
-
- private boolean symbolic_dur_flag;
- /* true if last dur was not absolute
- * (if this is set, then the default duration is changed
- * accordingly when the tempo is changed.)
- */
-
- private boolean ctrlflag[nctrl];
- /* true if control change was present
- * ctrlflag[0] true if ANY control change
- * was present
- */
- private int ctrlval[nctrl];
- /* the new value of the control */
-
- private int new_prog = -1;
- private int last_prog[num_voices];/*saved value of program from previous line */
- /* (this is needed to implement the rule that note
- * events are generated for rests if the program has changed.)
- */
-
- /****************************************************************************
- * state variables
- * Because each line of an Adagio score inherits properties from the previous
- * line, it makes sense to implement the parser as a collection of routines
- * that make small changes to some global state. For example, pitch is a
- * global variable. When the field G4 is encountered, the dopitch routine
- * assigns the pitch number for G4 to the variable pitch. After all fields
- * are processed, these variables describe the current note and contain the
- * default parameters for the next note as well.
- *
- * Global variables that are used in this way by the parsing rountines are:
- ****************************************************************************/
- private int
- linex, /* index of the next character to be scanned */
- lineno, /* current line number */
- fieldx, /* index of the current character within a field */
- pitch, /* pitch of note */
- loud, /* loudness of note */
- voice; /* voice (midi channel) of note */
-
- private boolean ndurp; /* set when a next (N) is indicated */
- /* (next time defaults to the current time plus duration unless
- * overridden by a next (N) command whose presence is signalled
- * by ndurp.)
- */
-
- private long
- thetime, /* the starting time of the note */
- thetrack, /* the midi track of the note */
- thecontrol, /* the controller */
- rate, /* time rate -- scales time and duration, default = 100 */
- ntime, /* the starting time of the next note */
- dur, /* the duration of the note */
- tempo, /* the current tempo */
- start; /* the reference time (time of last !tempo or !rate cmd) */
-
- private int pitchtable[7] = { 57, 59, 48, 50, 52, 53, 55 };
-
- extern char score_na[name_length];
-
- private int note_count = 0; /* the number of notes translated */
- private int ctrl_count = 0; /* ditto for control commands */
-
-
- /****************************************************************************
- * init
- * Outputs: Returns true if OK, false on error.
- * Effect: Initializes program state.
- ****************************************************************************/
-
- private boolean ad_init()
- {
- int i;
-
- /* see if any notes were played on the percussion channels,
- * if not, no need to ask for perc mode and lose voices
- */
- /*if (drum_mode) {*/
- for (i = 0; i < num_voices; i++) if (program[i] < 0)
- percsel &= ~(1 << i);
- if (!percsel) drum_mode = 0;
- /*}*/
-
- for (i = 0; i < nctrl; i++) ctrlflag[i] = false;
-
- dur = precise ((long) 60); /* quarter note */
- lineno = 0;
- thetime = 0;
- thetrack = 0;
- pitch = 48;
- loud = 127;
- voice = 1;
- for (i = 0; i < num_voices; i++) last_prog[i] = -1;
- tempo = 100;
- rate = 100;
- start = 0;
- symbolic_dur_flag = true; /*scale dur by tempo*/
- return true;
- }
-
- /****************************************************************************
- * ins_note
- * Inputs:
- * event_type *score: a linked list in which to insert
- * Outputs:
- * returns true on success, false on error (not enough space)
- * Effect:
- * note event (if any) corresponding to current line are inserted in
- * score
- * Implementation:
- * if a note on should occur after a note off and doesn't, and the
- * two notes have the same pitch, then the note off can cancel the
- * note on:
- * |------------------| <- this cancels *
- * this -> |-----------|
- * To make it unlikely that roundoff will cause this situation,
- * dur is decreased by one half of a clock tick before rounding.
- * Also, phase2 gives precedence to note-offs that are simultaneous
- * with note-ons.
- ****************************************************************************/
-
- private boolean ins_note(score)
- event_type *score;
- {
- event_type nalloc(), note;
- if ((note = nalloc()) == NULL) {
- return false;
- }
- note->ntime = round(thetime);
- note->nvoice = voice - 1;
- note->nline = lineno;
- note->ntrack = thetrack;
- note->next = NULL;
- if (rest_flag) note->u.note.npitch = NO_PITCH; /* a rest */
- else note->u.note.npitch = pitch;
- note->u.note.ndur = round(dur - (unity/2));
- note->u.note.nloud = loud;
- if (program[voice-1] > 0) {
- note->u.note.nprogram = program[voice-1];
- if (ext_chan[voice-1] && ext_program[ext_chan[voice-1]-1] == program[voice-1])
- note->ndest = ext_chan[voice-1];
- else note->ndest = 0;
- }
- else {
- note->u.note.nprogram = 1;
- program[voice - 1] = 0;
- note->ndest = 0;
- }
- if (vverbose)
- fprintf(stderr,
- "note: track=%d time=%ld dur=%ld pitch=%d voice=%d prog=%d vel=%d\n",
- note->ntrack, note->ntime, note->u.note.ndur, note->u.note.npitch,
- note->nvoice, note->u.note.nprogram, note->u.note.nloud);
- ins_event(score, note);
- return true;
- }
-
- private void doctrl(n, v)
- int n, v;
- {
- ctrlval[n] = v;
- ctrlflag[n] = true;
- ctrlflag[0] = true; /* ctrlflag[0] set if any flag is set */
- }
-
-
- /****************************************************************************
- * ins_ctrl
- * Inputs:
- * event_type *score: a linked list in which to insert
- * Outputs:
- * returns true on success, false on error (not enough space)
- * Effect:
- * control events corresponding to current line are inserted in score
- * Implementation:
- * ctrlflag[i] is true if control i was specified in this line, so
- * insert one control change for each ctrlflag[i] that is true
- ****************************************************************************/
-
- private boolean ins_ctrl(score)
- event_type *score;
- {
- int i;
- event_type ctrl;
-
- for (i = 1; i < nctrl; i++) {
- if (ctrlflag[i]) {
- ctrlflag[i] = false;
- if ((ctrl = ctrlalloc()) == NULL) {
- return false;
- }
- ctrl->ntime = round(thetime);
- ctrl->nvoice = ctrl_voice(i, voice-1);
- if (program[voice-1] > 0) {
- if (ext_chan[voice-1] && ext_program[ext_chan[voice-1]-1] == program[voice-1])
- ctrl->ndest = ext_chan[voice-1];
- else ctrl->ndest = 0;
- }
- else ctrl->ndest = 0;
- ctrl->nline = lineno;
- ctrl->ntrack = thetrack;
- ctrl->next = NULL;
- ctrl->u.ctrl.value = ctrlval[i];
- ctrl->u.ctrl.control = thecontrol;
- if (vverbose)
- fprintf(stderr,
- "ctrl: time=%ld voice=%d line=%d val=%d\n",
- ctrl->ntime, ctrl->nvoice, ctrl->nline, ctrl->u.ctrl.value);
- ins_event(score, ctrl);
- ctrl_count ++;
- }
- }
- return true;
- }
-
- /****************************************************************************
- * parsenote
- * Inputs:
- * event_type *scoreptr: pointer to the note list
- * Effect:
- * parses a note line -- control events (if any) and note event (if
- * present) are inserted into *scoreptr
- * Assumes:
- * line contains a string to be parsed
- ****************************************************************************/
-
- private boolean parsenote(scoreptr)
- event_type *scoreptr; /* the translated note list */
- {
- boolean out_of_memory = false;
-
- ndurp = false;
-
- if (!piano_only && new_prog >= 0) program[voice-1] = new_prog;
-
- /* try controls first (see note below) -- gl */
- if (ctrlflag[0]) {
- out_of_memory |= !ins_ctrl(scoreptr);
- /*ctrlflag[0] = false;*/
- }
-
- /* insert a note if
- * (1) a pitch was specified OR
- * (2) no control was specified and this is not a rest
- * (it's a pitch by default) OR
- * (3) there is a program change (even if this is a rest)
- *
- * NOTE: program changes during rests are advised since
- * synthesizers may not be able to process a program
- * change followed immediately by a note-on. In fact, this
- * is why we insert notes whose pitch is NO_PITCH -- so that
- * the program change can be processed during the rest.
- */
- if (pitch_flag ||
- (!ctrlflag[0] && !rest_flag) ||
- (program[voice-1] != last_prog[voice-1])) {
- out_of_memory = !ins_note(scoreptr);
- note_count ++;
- }
- /*
- * insert ctrl's last so that when the score is reversed,
- * they will be first.
- */
- /* above strategy does not seem to work, so I have moved this
- to before a note is generated. Then ctrl's really do wind
- up before notes, when times are equal -- gl */
- /*
- if (ctrlflag[0]) {
- out_of_memory |= !ins_ctrl(scoreptr);
- ctrlflag[0] = false;
- }
- */
-
- /* but still have to note that the ctrl's have now been generated -- gl */
- ctrlflag[0] = false;
-
- last_prog[voice-1] = program[voice-1];
- new_prog = -1;
-
- if (ndurp) thetime += ntime;
- else thetime += dur;
-
- return out_of_memory;
- }
-
-
-
- /****************************************************************************
- * phasem (adapted from "output" routine of transcribe and "phase1")
- * Inputs:
- * m_note_type last: the last data in the buffer
- * boolean absflag: set to true if first line of the adagio score should
- * include the absolute time
- * Effect:
- * write adagio score using data in event_buff
- * Implementation:
- * NOTE: put all program changes in rests
- * use N(ext) notation for all timing
- * output no more than one continuous parameter change per
- * clock tick for each continuous change parameter
- ****************************************************************************/
-
- private event_type phasem(last, absflag)
- m_note_type last;
- boolean absflag;
- {
- int i; /* loop counter */
- int command; /* the current command */
- int chan; /* the midi channel of the current event */
- int lastchan = 0; /* the default adagio channel (1) */
- int ped = false; /* flag maintains state of pedal */
- int how_many = last - event_buff;
- long now; /* the time of the next event */
- boolean bad_ctrl_flag = false; /* set to true if unknown ctrl read */
- boolean nxlie = false;
- /* variables from "phase1" */
- event_type score = NULL; /* the translated note list */
- boolean out_of_memory = false; /* set when no more memory */
-
- if (!ad_init()) { /* something bad happened in init(), STOP */
- fprintf(stderr,"WOOPS; something strange happened in INIT()! ...exiting\n");
- exit(1);
- return NULL; /* make lint happy */
- }
- lineno = 0;
-
-
- /* set the initial absolute time, all other times are relative */
- if (absflag && ad_print)
- printf("t%ld ", round(event_buff[0].when));
-
- for (i = 0; i < how_many; i++) {
- if (vverbose) {
- printf("ev %d: %x %x %x (%ld)\n", i, event_buff[i].n[0],
- event_buff[i].n[1], event_buff[i].n[2], event_buff[i].when);
- }
- if (istime(event_buff+i)) {
- now = event_buff[i].when;
- if (vverbose) printf("i = %d, now = %ld\n", i, now);
- } else {
- command = event_buff[i].n[0] & MIDI_CODE_MASK;
- chan = event_buff[i].n[0] & MIDI_CHN_MASK;
-
- if ( nxlie &&
- (command != MIDI_ON_NOTE || event_buff[i].n[2] != 0)
- ) {
- if (ad_print) printf("t%ld ", round(now));
- nxlie = false;
- }
-
- pitch_flag = false;
- thetime = now;
- voice = chan + 1;
- thetrack = event_buff[i].n[3] & 0x7f;
- dur = 0;
- rest_flag = true;
- if (command == MIDI_CTRL) thecontrol = event_buff[i].n[1];
- else thecontrol = -1;
-
- if (command == MIDI_ON_NOTE && event_buff[i].n[2] != 0) {
- int solo;
- pitch = event_buff[i].n[1] - 12;
- pitch_flag = true;
- rest_flag = false;
- if (!(percsel&(1 << chan)) && program[chan] > 0)
- solo = sub_voice[program[chan]-1].solo;
- else solo = 0;
- dur = getdur(i, last, ped, now, solo);
- loud = event_buff[i].n[2];
-
- if (ad_print) {
- put_pitch(pitch);
- printf(" u%ld l%d n%ld", round(dur), loud,
- round(diffnext(i,last,now,&nxlie)));
- if (lastchan != chan) {
- printf(" v%d\n", chan + 1);
- lastchan = chan;
- } else printf("\n");
- }
- } else if (command == MIDI_CH_PROGRAM) {
- new_prog = event_buff[i].n[1];
-
- if (ad_print) {
- printf("r z%d n%ld", event_buff[i].n[1],
- round(diffnext(i,last,now,&nxlie)));
- /**
- if (lastchan != chan) {
- printf(" v%d\n", chan + 1);
- } else printf("\n");
- **/
- printf(" v%d\n", chan + 1);
- }
- } else if (command == MIDI_CTRL &&
- event_buff[i].n[1] == SUSTAIN) {
- ped = (event_buff[i].n[2] != 0);
- } else if (command == MIDI_CTRL) {
- char c = map_ctrl(thecontrol);
- int n = map_nctrl(thecontrol);
- if (thecontrol == PAN && ext_pan[chan] == -1)
- ext_pan[chan] = event_buff[i].n[2];
- if (n != 0) doctrl(n, event_buff[i].n[2]);
- if (c != 0) {
- if (ad_print) printf("%c%d n%d\n", c,
- event_buff[i].n[2], round(diffnext(i,last,now,&nxlie)));
- } else if (n == 0) bad_ctrl_flag = true;
- } else if (command == MIDI_TOUCH) {
- doctrl(4, event_buff[i].n[1]);
- if (ad_print) printf("O%d n%d\n", event_buff[i].n[1],
- round(diffnext(i,last,now,&nxlie)));
- } else if (command == MIDI_POLY_TOUCH) {
- /* perhaps this would be unwise
- doctrl(4, event_buff[i].n[1]);
- if (ad_print) printf("O%d n%d\n", event_buff[i].n[1],
- round(diffnext(i,last,now,&nxlie)));
- */
- } else if (command == MIDI_BEND) {
- doctrl(6, event_bend(&event_buff[i]));
- if (ad_print) {
- printf("Y%d n%d", event_bend(&event_buff[i]),
- round(diffnext(i,last,now,&nxlie)));
- if (lastchan != chan) printf(" v%d\n", chan + 1);
- else printf("\n");
- }
- } else if (command != MIDI_ON_NOTE) {
- if (verbose) fprintf(stderr, "Command 0x%x ignored\n", command);
- }
-
- if (pitch_flag || ctrlflag[0] || lastchan != chan || new_prog > 0)
- out_of_memory = parsenote(&score);
- lastchan = chan;
- }
- }
-
- if (bad_ctrl_flag && verbose)
- fprintf(stderr,
- "Some unrecognized control changes were omitted from file.\n");
-
- if (out_of_memory) {
- fprintf(stderr,"Out of note memory at line %d,\n", lineno-1);
- fprintf(stderr," the rest of your file will be ignored.\n");
- }
-
- if (verbose)
- printf (
- "Phase 1 completed; %d note(s), %d ctrl(s) have been translated.\n\n",
- note_count, ctrl_count);
-
- free(event_buff);
- reverse(&score);
- return score;
- }
-
- /****************************************************************************
- * put_pitch
- * Inputs:
- * FILE *fp: an open file
- * int p: a pitch number
- * Effect: write out the pitch name for a given number
- ****************************************************************************/
-
- private void put_pitch(p)
- int p;
- {
- static char *ptos[] = {"c", "cs", "d", "ef", "e", "f", "fs", "g",
- "gs", "a", "bf", "b"};
- printf("%s%d", ptos[p % 12], p / 12);
- }
-
- /**********************************************************************
- * rec_final
- * Inputs:
- * boolean absflag: output absolute time of first m_note if true
- * Effect:
- * Write recorded data to a file
- **********************************************************************/
-
- /*private void rec_final(absflag)*/
- private event_type rec_final(absflag)
- boolean absflag;
- {
- next->when = m_time();
- last = next;
- /*if (verbose) printf("max_pile_up = %d, ", max_pile);*/
- if (verbose) printf(" %d times and events recorded.\n", last - event_buff);
- filter(last);
- return(phasem(last, absflag));
- }
-
- /****************************************************************************
- * rec_init
- * Inputs:
- * char *file: pointer to file name from command line (if any)
- * boolean bender: true if pitch bend should be enabled
- * Outputs:
- * returns true if initialization succeeds
- * Effect:
- * prepares module to record midi input
- ****************************************************************************/
-
- private void rec_init()
- {
- #ifndef linux
- char *malloc(); /* memory allocation */
- #endif
- pile_ups = 0;
- max_pile = 0;
-
- if (max_m_notes == -1) { /* allocate space 1st time rec_init called */
- max_m_notes = space/sizeof(m_note_node);
- event_buff = (m_note_type) malloc(sizeof(m_note_node) * max_m_notes);
- if (event_buff == NULL) {
- fprintf(stderr, "Internal error allocating record space.");
- exit(1);
- }
- byteorder();
- if (verbose)
- printf("Space for %d events has been allocated.\n", max_m_notes);
- }
- next = event_buff;
- last = event_buff + max_m_notes - 2;
-
-
- return;
- }
-
- long
- m_time()
- {
- double time;
-
- time = mf_ticks2sec(Mf_currtime,m_division,m_tempo);
- return( (unsigned long) (time * 100 * 256));
- }
-
- #if 0
- /****************************************************************************
- * parsenote
- * Inputs:
- * event_type *scoreptr: pointer to the note list
- * Effect:
- * parses a note line -- control events (if any) and note event (if
- * present) are inserted into *scoreptr
- * Assumes:
- * line contains a string to be parsed
- ****************************************************************************/
-
- private boolean parsenote(scoreptr)
- event_type *scoreptr; /* the translated note list */
- {
- boolean out_of_memory = false;
-
- ndurp = false;
- rest_flag = false;
-
- /* this loop reads tokens for a note */
- while (strlen(token) > 0) {
- parsefield();
- linex += scan(&line[linex]);
- }
-
- parseend(); /* take care of note terminator */
-
- if (new_prog >= 0) program[voice-1] = new_prog;
-
- /* try controls first (see note below) -- gl */
- if (ctrlflag[0]) {
- out_of_memory |= !ins_ctrl(scoreptr);
- /*ctrlflag[0] = false;*/
- }
-
- /* insert a note if
- * (1) a pitch was specified OR
- * (2) no control was specified and this is not a rest
- * (it's a pitch by default) OR
- * (3) there is a program change (even if this is a rest)
- *
- * NOTE: program changes during rests are advised since
- * synthesizers may not be able to process a program
- * change followed immediately by a note-on. In fact, this
- * is why we insert notes whose pitch is NO_PITCH -- so that
- * the program change can be processed during the rest.
- */
- if (pitch_flag ||
- (!ctrlflag[0] && !rest_flag) ||
- (program[voice-1] != last_prog[voice-1])) {
- out_of_memory = !ins_note(scoreptr);
- note_count ++;
- }
- /*
- * insert ctrl's last so that when the score is reversed,
- * they will be first.
- */
- /* above strategy does not seem to work, so I have moved this
- to before a note is generated. Then ctrl's really do wind
- up before notes, when times are equal -- gl */
- /*
- if (ctrlflag[0]) {
- out_of_memory |= !ins_ctrl(scoreptr);
- ctrlflag[0] = false;
- }
- */
-
- /* but still have to note that the ctrl's have now been generated -- gl */
- ctrlflag[0] = false;
-
- last_prog[voice-1] = program[voice-1];
- new_prog = -1;
-
- if (ndurp) thetime += ntime;
- else thetime += dur;
-
- return out_of_memory;
- }
-
- /****************************************************************************
- * phase1
- * Inputs:
- * FILE *fp: input file
- * Outputs:
- * returns event_type: the parsed score
- * Effect:
- * parses score from input file and builds score data structure
- ****************************************************************************/
-
- event_type phase1(fp)
- FILE *fp;
- {
- event_type score = NULL; /* the translated note list */
- boolean out_of_memory = false; /* set when no more memory */
-
- if (!init()) { /* something bad happened in init(), STOP */
- fprintf(stderr,"WOOPS; something strange happened in INIT()! ...exiting\n");
- exit(1);
- return NULL; /* make lint happy */
- }
-
- lineno = 0;
-
- /* this loop reads lines */
- while ((fgets(line, linesize, fp) != NULL) && !out_of_memory) {
- lineno++;
- linex = 0;
- /* this loop reads notes from a line */
- while ((line[linex] != 0) && !out_of_memory) {
- /* loop invariant: line[linex] is first char of next note */
- pitch_flag = false;
- linex += scan(&line[linex]);
- if (!nullstring(token)) {
- if (token[0] == '*') docomment();
- else if (token[0] == '!') dospecial();
- else out_of_memory = parsenote(&score);
- } else parseend();
- }
- }
-
-
- if (out_of_memory) {
- fprintf(stderr,"Out of note memory at line %d,\n", lineno-1);
- fprintf(stderr," the rest of your file will be ignored.\n");
- }
-
- if (verbose)
- printf (
- "\nPhase 1 completed; %d note(s), %d ctrl(s) have been translated.\n",
- note_count, ctrl_count);
-
- reverse(&score);
- return score;
- }
- #endif
-
- /****************************************************************************
- * reverse
- * Inputs:
- * event_type *p: pointer to a list of notes and control events
- * Effect: reverses note and control events in p
- ****************************************************************************/
-
- private void reverse(p)
- event_type *p;
- {
- event_type p1, p2, p3;
- p1 = *p;
- if (p1 == NULL) return;
- p2 = p1->next;
- p1->next = NULL;
- while (p2 != NULL) {
- p3 = p2->next;
- p2->next = p1;
- p1 = p2;
- p2 = p3;
- }
- *p = p1;
- }
-
- /****************************************************************************
- * ins_event
- * Inputs:
- * event_type *p: a linked list in which to insert
- * event_type event: the new event to insert
- * Effect:
- * inserts event into score in reverse time order (this makes inserts
- * that are sequential in time go fast)
- ****************************************************************************/
-
- private void ins_event(p, event)
- event_type *p; /* the score */
- event_type event; /* the new event to insert */
- {
- event_type ptr = *p;
- event_type prv;
-
- if (ptr == NULL || event->ntime >= ptr->ntime) {
- event->next = ptr; /* insert at head of list */
- *p = event;
- } else { /* list insert */
- while (ptr != NULL && event->ntime < ptr->ntime) {
- prv = ptr;
- ptr = ptr->next;
- }
- prv->next = event;
- event->next = ptr;
- }
- }
-
-
- /****************************************************************************
- * nalloc
- * Outputs: returns event_type for an event allocated from heap, NULL on error
- * Effect: allocates memory, decreases space accordingly
- ****************************************************************************/
-
- private event_type nalloc()
- {
- #ifndef linux
- char *malloc();
- #endif
- event_type result;
- space -= sizeof(struct event_struct);
- if (space > 0) {
- result = ((event_type ) malloc (sizeof(struct event_struct)));
- if (result == NULL)
- printf("Internal error: Out of memory, space = %ld.\n",space);
- } else result = NULL;
- return result;
- }
-
- /****************************************************************************
- * ctrlalloc
- * Outputs: returns an event_type for representing a control change
- * returns NULL if space is unavailable
- * Effect: allocates ctrlsize bytes
- * Assumes: space tells how many bytes are available
- ****************************************************************************/
- private event_type ctrlalloc()
- {
- #ifndef linux
- char *malloc();
- #endif
- event_type result;
- space -= ctrlsize;
- if (space > 0) {
- result = (event_type ) malloc(ctrlsize);
- if (result == NULL) /* this should never happen ... */
- printf("Internal error: Out of memory, space = %ld.\n",space);
- } else result = NULL;
- return result;
- }
-
-